package edu.ynu.se.xiecheng.achitectureclass.soildata.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.ynu.se.xiecheng.achitectureclass.device.entity.Device;
import edu.ynu.se.xiecheng.achitectureclass.device.service.DeviceService;
import edu.ynu.se.xiecheng.achitectureclass.soildata.dao.*;
import edu.ynu.se.xiecheng.achitectureclass.soildata.entity.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.client.HttpClientErrorException;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.HashMap;
import java.util.Date;

@Service
public class SoilDataCollectorService {

    private static final Logger logger = LoggerFactory.getLogger(SoilDataCollectorService.class);

    @Value("${fbox.data_url}")
    private String dataUrl;

    private final FboxTokenService tokenService;
    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;
    private final DeviceService deviceService;

    private final SoilMoistureDataDAO soilMoistureDataDAO;
    private final SoilTemperatureDataDAO soilTemperatureDataDAO;
    private final SoilConductivityDataDAO soilConductivityDataDAO;
    private final SoilPHDataDAO soilPHDataDAO;
    private final SoilNitrogenDataDAO soilNitrogenDataDAO;
    private final AirTemperatureDataDAO airTemperatureDataDAO;
    private final AirHumidityDataDAO airHumidityDataDAO;
    private final CO2DataDAO co2DataDAO;
    private final LightIntensityDataDAO lightIntensityDataDAO;
    private final SoilPhosphorusDataDAO soilPhosphorusDataDAO;
    private final SoilPotassiumDataDAO soilPotassiumDataDAO;

    @Autowired
    public SoilDataCollectorService(FboxTokenService tokenService,
                                    SoilMoistureDataDAO soilMoistureDataDAO,
                                    SoilTemperatureDataDAO soilTemperatureDataDAO,
                                    SoilConductivityDataDAO soilConductivityDataDAO,
                                    SoilPHDataDAO soilPHDataDAO,
                                    SoilNitrogenDataDAO soilNitrogenDataDAO,
                                    SoilPhosphorusDataDAO soilPhosphorusDataDAO,
                                    SoilPotassiumDataDAO soilPotassiumDataDAO,
                                    DeviceService deviceService,
                                    AirTemperatureDataDAO airTemperatureDataDAO,
                                    AirHumidityDataDAO airHumidityDataDAO,
                                    CO2DataDAO co2DataDAO,
                                    LightIntensityDataDAO lightIntensityDataDAO) {
        this.tokenService = tokenService;
        this.soilMoistureDataDAO = soilMoistureDataDAO;
        this.soilTemperatureDataDAO = soilTemperatureDataDAO;
        this.soilConductivityDataDAO = soilConductivityDataDAO;
        this.soilPHDataDAO = soilPHDataDAO;
        this.soilNitrogenDataDAO = soilNitrogenDataDAO;
        this.soilPhosphorusDataDAO = soilPhosphorusDataDAO;
        this.soilPotassiumDataDAO = soilPotassiumDataDAO;
        this.deviceService = deviceService;
        this.airTemperatureDataDAO = airTemperatureDataDAO;
        this.airHumidityDataDAO = airHumidityDataDAO;
        this.co2DataDAO = co2DataDAO;
        this.lightIntensityDataDAO = lightIntensityDataDAO;
        this.restTemplate = new RestTemplate();
        this.objectMapper = new ObjectMapper();
    }

    /**
     * 手动采集土壤传感器数据并存储
     *
     * @param greenhouseNumber 大棚编号
     */
    @Transactional(rollbackFor = Exception.class)
    public void collectAndStoreData(String greenhouseNumber) throws Exception {
        try {
            String accessToken = tokenService.getAccessToken();
            logger.debug("Access Token: {}", accessToken);

            List<Device> soilDevices = deviceService.getSoilDevices(greenhouseNumber);
            if (soilDevices.isEmpty()) {
                logger.error("大棚 {} 下没有配置的土壤检测设备", greenhouseNumber);
                throw new RuntimeException("大棚编号 " + greenhouseNumber + " 下没有配置的土壤检测设备");
            }

            logger.info("获取到 {} 个土壤检测设备", soilDevices.size());

            // 过滤掉摄像头设备（设备类型为CAMERA的设备）
            List<String> sensorIds = soilDevices.stream()
                    .filter(device -> !"CAMERA".equals(device.getCategory()))  // 过滤掉摄像头
                    .map(Device::getDeviceNumber)
                    .collect(Collectors.toList());

            if (sensorIds.isEmpty()) {
                throw new IllegalArgumentException("没有可用的传感器设备");
            }

            logger.debug("调用API的boxNo: {}，传感器IDs: {}", greenhouseNumber, sensorIds);

            // 构建请求体
            String jsonBody = objectMapper.writeValueAsString(Map.of("ids", sensorIds));
            logger.debug("请求体: {}", jsonBody);

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.setBearerAuth(accessToken);

            // 使用String作为请求体，确保JSON格式的完整性
            HttpEntity<String> request = new HttpEntity<>(jsonBody, headers);

            // 发送POST请求
            ResponseEntity<String> response = restTemplate.postForEntity(
                dataUrl + "?boxNo=" + greenhouseNumber, 
                request, 
                String.class
            );

            // 记录完整的请求和响应信息，方便调试
            logger.debug("完整请求URL: {}", dataUrl + "?boxNo=" + greenhouseNumber);
            logger.debug("请求头: {}", headers);
            logger.debug("响应状态: {}", response.getStatusCode());
            logger.debug("响应体: {}", response.getBody());

            if (response.getStatusCode() == HttpStatus.OK) {
                JsonNode jsonResponse = objectMapper.readTree(response.getBody());
                logger.debug("响应内容: {}", jsonResponse);

                if (jsonResponse.isArray()) {
                    for (JsonNode dataNode : jsonResponse) {
                        try {
                            if (dataNode == null || dataNode.isNull()) {
                                logger.warn("收到 null 数据节点，跳过处理");
                                continue;
                            }

                            // 解析和保存数据的代码移到单独的方法中
                            processAndSaveData(dataNode, soilDevices);
                        } catch (Exception e) {
                            logger.error("处理单个数据节点时出错: {}", e.getMessage(), e);
                            // 继续处理下一个节点，不中断整个过程
                        }
                    }
                } else {
                    logger.warn("响应内容不是数组格式，跳过处理");
                }
            } else if (response.getStatusCode() == HttpStatus.UNAUTHORIZED) {
                logger.warn("Token失效，正在刷新Token");
                tokenService.refreshToken();
                collectAndStoreData(greenhouseNumber);
            } else {
                logger.error("获取数据失败，状态码：{}", response.getStatusCode());
                throw new RuntimeException("获取数据失败，状态码：" + response.getStatusCode());
            }

        } catch (Exception e) {
            logger.error("数据采集失败: {}", e.getMessage(), e);
            throw e; // 直接抛出异常，让事务管理器处理回滚
        }
    }

    private void processAndSaveData(JsonNode dataNode, List<Device> soilDevices) {
        String sensorId = dataNode.has("id") && !dataNode.get("id").isNull() ? dataNode.get("id").asText() : "unknown";
        String name = dataNode.has("name") && !dataNode.get("name").isNull() ? dataNode.get("name").asText() : "unknown";
        double value = dataNode.has("value") && !dataNode.get("value").isNull() ? dataNode.get("value").asDouble() : 0.0;

        logger.info("处理传感器数据 - ID: {}, 名称: {}, 值: {}", sensorId, name, value);

        Device device = getDeviceByNumber(sensorId, soilDevices);
        if (device == null) {
            logger.warn("未找到对应的设备，传感器ID: {}", sensorId);
            return;
        }

        BaseSensorData sensorData = createSensorData(name, device, value);
        if (sensorData != null) {
            saveSensorData(sensorData);
        }
    }

    private BaseSensorData createSensorData(String name, Device device, double value) {
        BaseSensorData sensorData = null;
        Date now = new Date(); // 获取当前时间
        
        switch (name) {
            case "土壤含水率":
                sensorData = new SoilMoistureData();
                break;
            case "土壤温度":
                sensorData = new SoilTemperatureData();
                break;
            case "土壤电导率":
                sensorData = new SoilConductivityData();
                break;
            case "土壤PH值":
                sensorData = new SoilPHData();
                break;
            case "土壤氮含量":
                sensorData = new SoilNitrogenData();
                break;
            case "土壤磷含量":
                sensorData = new SoilPhosphorusData();
                break;
            case "土壤钾含量":
                sensorData = new SoilPotassiumData();
                break;
            case "二氧化碳":
                sensorData = new CO2Data();
                break;
            case "空气温度":
                sensorData = new AirTemperatureData();
                break;
            case "空气相对湿度":
                sensorData = new AirHumidityData();
                break;
            case "光照度":
                sensorData = new LightIntensityData();
                break;
            default:
                logger.warn("未知的传感器类型: {}", name);
                return null;
        }

        if (sensorData != null) {
            sensorData.setDevice(device);
            sensorData.setName(name);
            sensorData.setValue(value);
            sensorData.setCreateTime(now);  // 设置创建时间
            sensorData.setUpdateTime(now);  // 设置更新时间
        }
        return sensorData;
    }

    private void saveSensorData(BaseSensorData sensorData) {
        try {
            if (sensorData instanceof SoilMoistureData) {
                soilMoistureDataDAO.save((SoilMoistureData) sensorData);
            } else if (sensorData instanceof SoilTemperatureData) {
                soilTemperatureDataDAO.save((SoilTemperatureData) sensorData);
            } else if (sensorData instanceof SoilConductivityData) {
                soilConductivityDataDAO.save((SoilConductivityData) sensorData);
            } else if (sensorData instanceof SoilPHData) {
                soilPHDataDAO.save((SoilPHData) sensorData);
            } else if (sensorData instanceof SoilNitrogenData) {
                soilNitrogenDataDAO.save((SoilNitrogenData) sensorData);
            } else if (sensorData instanceof SoilPhosphorusData) {
                soilPhosphorusDataDAO.save((SoilPhosphorusData) sensorData);
            } else if (sensorData instanceof SoilPotassiumData) {
                soilPotassiumDataDAO.save((SoilPotassiumData) sensorData);
            } else if (sensorData instanceof CO2Data) {
                co2DataDAO.save((CO2Data) sensorData);
            } else if (sensorData instanceof AirTemperatureData) {
                airTemperatureDataDAO.save((AirTemperatureData) sensorData);
            } else if (sensorData instanceof AirHumidityData) {
                airHumidityDataDAO.save((AirHumidityData) sensorData);
            } else if (sensorData instanceof LightIntensityData) {
                lightIntensityDataDAO.save((LightIntensityData) sensorData);
            } else {
                logger.error("未知的传感器数据类型: {}", sensorData.getClass().getName());
                throw new IllegalArgumentException("未知的传感器数据类型");
            }
            logger.info("保存{}数据成功", sensorData.getName());
        } catch (Exception e) {
            logger.error("保存{}数据失败: {}", sensorData.getName(), e.getMessage(), e);
            throw e;
        }
    }

    /**
     * 根据传感器ID从设备列表中获取对应的设备实体
     *
     * @param sensorId    传感器ID（deviceNumber）
     * @param soilDevices 设备列表
     * @return 设备实体
     */
    private Device getDeviceByNumber(String sensorId, List<Device> soilDevices) {
        return soilDevices.stream()
                .filter(d -> d.getDeviceNumber().equals(sensorId))
                .findFirst()
                .orElseThrow(() -> new RuntimeException("未找到对应的设备，传感器ID: " + sensorId));
    }

    private boolean isValidDeviceId(String deviceId) {
        try {
            // 根据实际需求验证设备ID格式
            return deviceId != null && deviceId.matches("^[0-9]+$");
        } catch (Exception e) {
            return false;
        }
    }
}
